 /**
  * MOTOR 2 - RAPID FLASH DYNAMICS
  * Copyright (c) 2006-2008 Michael Baczynski http://www.polygonal.de
  *
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * arising from the use of this software.
  * 
  * Permission is granted to anyone to use this software for any purpose,
  * including commercial applications, and to alter it and redistribute it
  * freely, subject to the following restrictions:
  * 
  * 1. The origin of this software must not be misrepresented; you must not
  * claim that you wrote the original software. If you use this software
  * in a product, an acknowledgment in the product documentation would be
  * appreciated but is not required.
  * 2. Altered source versions must be plainly marked as such, and must not be
  * misrepresented as being the original software.
  * 3. This notice may not be removed or altered from any source distribution.
  */
package de.polygonal.motor2.dynamics.contact.generator
{
	import de.polygonal.motor2.collision.pairwise.CollideBoxCircle;
	import de.polygonal.motor2.collision.shapes.ShapeSkeleton;
	import de.polygonal.motor2.dynamics.contact.Contact;
	import de.polygonal.motor2.dynamics.contact.ContactPoint;
	import de.polygonal.motor2.dynamics.contact.Manifold;
	import de.polygonal.motor2.math.V2;	

	public class BoxCircleContact extends Contact
	{	
		public var manifold:Manifold;
		
		public var v0:V2;
		public var n0:V2;
		
		private var _m0Cp1:ContactPoint, _m1Cp1:ContactPoint;
		private var _m0:Manifold;
		
		public static function create(shape1:ShapeSkeleton, shape2:ShapeSkeleton):Contact
		{
			return new BoxCircleContact(shape1, shape2);
		}
		
		public static function destroy():void
		{
			//TODO optimize: recycle used manifold
		}
		
		public function BoxCircleContact(shape1:ShapeSkeleton, shape2:ShapeSkeleton)
		{
			super(shape1, shape2);
			
			//TODO optimize: create manifold buffer queue
			manifold = manifolds[0] = new Manifold(); 
			_m0 = new Manifold();
			
			_m0Cp1 = _m0.c0; _m1Cp1 = manifold.c0;
			
			_collider = new CollideBoxCircle();
			
			v0 = shape1.worldVertexChain;
			n0 = shape1.worldNormalChain;
		}
		
		override public function evaluate():void
		{
			if (!shape1.synced) shape1.toWorldSpace();
			
			var k0:int, k1:int;
			
			/* store impulses from previous time step */
			if (_doWarmStart)
			{
				manifold.c0.matched = false;
				
				k0 = manifold.pointCount;
				
				_m0.pointCount = k0;
				if (k0 > 0)
				{
					_m0Cp1.id = _m1Cp1.id.copy();
					_m0Cp1.Pn = _m1Cp1.Pn;
					_m0Cp1.Pt = _m1Cp1.Pt;
				}
			}
			
			/* create contact manifold */ 
			_collider.collide(manifold, shape1, shape2, this);
			if (manifold.pointCount > 0)
				manifoldCount = 1;
			else
			{
				manifoldCount = 0;
				return;
			}
			
			//TODO optimized matching for single contact point
			
			/* try to reapply impulses if contact id's match */
			if (_doWarmStart)
			{
				_m1Cp1.Pn = .0;
				_m1Cp1.Pt = .0;
				
				k1 = manifold.pointCount;
				if (k1 == 1)
				{
					if (k0 == 1)
					{
						/* match one new contact against one old contact */
						
						//compare new1 -> old1
						if (_m1Cp1.id.key == _m0Cp1.id.key)
						{
							_m1Cp1.Pn = _m0Cp1.Pn;
							_m1Cp1.Pt = _m0Cp1.Pt;
							_m1Cp1.matched = true;
						}
					}
				}
			}
		}
		
		override public function getConstructor():Class
		{
			return BoxCircleContact;	
		}
	}
}